/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package practica1.domain;

import beancomentarios.ComentarioEvent;
import beancomentarios.ComentarioListener;
import beancomentarios.ModeloComentarios;
import es.miguelgonzalez.jgraficacomida.GraficaComidaChangeEvent;
import es.miguelgonzalez.jgraficacomida.GraficaComidaChangeEventListener;
import es.miguelgonzalez.jgraficacomida.ModeloGraficaComida;
import java.util.ArrayList;
import java.util.Calendar;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import practica1.domain.event.PoblacionPropertyEvent;
import static practica1.domain.event.PoblacionPropertyEvent.*;
import practica1.domain.listener.PoblacionPropertyListener;
import practica1.ui.tablaPoblacion.ModeloPoblacionFactory;
import practica1.ui.tablaPoblacion.ModeloPoblacionTabla;
import practica1.util.HashCodeUtil;

/**
 * Clase que implementa el modelo de una población
 * @author Miguel González - Ceura
 */
public class Poblacion {
    //Escuchadores de nuestro modelo
    private ArrayList<PoblacionPropertyListener> propListeners;
    
    //Objetos del modelo
    private String nombrePoblacion;
    private String fecha;
    private int tamanioPoblacion;
    private int temperatura;
    private String escalaTemperatura;
    private String luminosidad;
    private ModeloGraficaComida modeloGraficaComida;
    private ModeloPoblacionTabla modeloPoblacionTabla;
    private ModeloComentarios modeloComentarios;
    
    /**
     * Constructor de una población
     * @param nombrePoblacion Recibe el nombre de la población
     */
    public Poblacion(String nombrePoblacion) {
        //Instanciamos los escuchadores de nuestro modelo
        propListeners = new ArrayList<PoblacionPropertyListener>();
        
        //Instanciamos los objetos del modelo
        this.nombrePoblacion = nombrePoblacion;
        Calendar calendario = Calendar.getInstance();
        fecha = calendario.get(Calendar.DAY_OF_MONTH) +
            "/" + calendario.get(Calendar.MONTH) + 
            "/" + calendario.get(Calendar.YEAR);
        tamanioPoblacion = 0;
        temperatura = 0;
        escalaTemperatura = "";
        luminosidad = "";
        modeloComentarios = new ModeloComentarios();
        
        modeloGraficaComida = new ModeloGraficaComida();
        modeloGraficaComida.addChangeEventListener(
                new GraficaComidaChangeEventListener() {
            @Override
            public void fireChangeEvent(GraficaComidaChangeEvent gcce) {
                modeloGraficaChange();
            }
            
        });
        
        modeloPoblacionTabla = ModeloPoblacionFactory.crearModeloTablaDefecto();
        modeloPoblacionTabla.addTableModelListener(new TableModelListener() {
            @Override
            public void tableChanged(TableModelEvent e) {
                modeloPoblacionChange();
            }
         });
        
        modeloComentarios.addComentarioListener(new ComentarioListener() {
            @Override
            public void addedComentario(ComentarioEvent ce) {
                modeloComentarioChange();
            }

            @Override
            public void removedComentario(ComentarioEvent ce) {
                modeloComentarioChange();
            }            
        });
    }
    
    /**
     * Devuelve el nombre de la población
     * @return String nombrePoblacion
     */
    @Override
    public String toString() {
        return nombrePoblacion;
    }

    /**
     * Método que compara un objeto con la población
     * @param poblacion Objeto de tipo Poblacion
     * @return Si el objeto es una población igual devuelve true, sino false
     */
    @Override
    public boolean equals(Object poblacion) {
        if(poblacion != null) {
            if(poblacion instanceof Poblacion) {
                Poblacion p = (Poblacion) poblacion;
                if(p.getFecha().equals(fecha) && p.getEscalaTemperatura().equals(
                        escalaTemperatura) && p.getLuminosidad().equals(luminosidad)
                        && p.getModeloGraficaComida().equals(modeloGraficaComida)
                        && p.getModeloPoblacionTabla().equals(modeloPoblacionTabla)
                        && p.getNombrePoblacion().equals(nombrePoblacion)
                        && p.getTamanioPoblacion() == tamanioPoblacion && 
                        p.getTemperatura() == temperatura) {
                    return true;
                }
            }
        }
        
        return false;
    }
    
    /**
     * Devuelve el hashCode de la población
     * @return int hashCode
     */
    @Override
    public int hashCode() {
        int result = HashCodeUtil.SEED;
        
        result = HashCodeUtil.hash(result, fecha);
        result = HashCodeUtil.hash(result, escalaTemperatura);
        result = HashCodeUtil.hash(result, luminosidad);
        result = HashCodeUtil.hash(result, modeloGraficaComida);
        result = HashCodeUtil.hash(result, modeloPoblacionTabla);
        result = HashCodeUtil.hash(result, nombrePoblacion);
        result = HashCodeUtil.hash(result, tamanioPoblacion);
        result = HashCodeUtil.hash(result, temperatura);
        
        return result;
    }
    
    /**
     * Notifica cuando el modelo de la gráfica cambia
     */
    private void modeloGraficaChange() {
        fireModeloPoblacionPropertyChange(new PoblacionPropertyEvent(
             this, CHANGE_MODELO_GRAFICA_COMIDA));   
    }
    
    /**
     * Notifica cuando cambia el modelo de la tabla
     */
    private void modeloPoblacionChange() {
        fireModeloPoblacionPropertyChange(new PoblacionPropertyEvent(
                this, CHANGE_MODELO_POBLACION_TABLA));
    }
    
    /**
     * Notififca cuando cambia el modelo del comentario
     */
    private void modeloComentarioChange() {
        fireModeloPoblacionPropertyChange(new PoblacionPropertyEvent(
                this, CHANGE_MODELO_COMENTARIOS));
    }
    
    /**
     * Permite suscribirse a los cambios de las propiedades de la población
     * @param l PoblacionPropertyListener
     */
    public void addPropertyChangeListener(PoblacionPropertyListener l) {
        propListeners.add(l);
    }
    
    /**
     * Permite desuscribirse a los cambios de las propiedades de la población
     * @param l PoblacionPropertyListener
     */
    public void removePropertyChangeListener(PoblacionPropertyListener l) {
        propListeners.remove(l);
    }
    
    /**
     * Notifica cuando cambia una de las propiedades de la población
     * @param propertyChange 
     */
    private void fireModeloPoblacionPropertyChange(
            PoblacionPropertyEvent propertyChange) {
        for(PoblacionPropertyListener l : propListeners) {
            l.propertyChange(propertyChange);
        }
    }
    
    /**
     * Devuelve el nombre de la población
     * @return String nombrePoblacion
     */
    public String getNombrePoblacion() {
        return nombrePoblacion;
    }

    /**
     * Establece el nuevo nombre de la población
     * @param nombrePoblacion String nombrePoblacion
     */
    public void setNombrePoblacion(String nombrePoblacion) {
        this.nombrePoblacion = nombrePoblacion;
        
        fireModeloPoblacionPropertyChange(new
                        PoblacionPropertyEvent(this, 
                        CHANGE_NOMBRE_POBLACION));
    }

    /**
     * Devuelve la fecha de la población
     * @return String fecha
     */
    public String getFecha() {
        return fecha;
    }

    /**
     * Establece la nueva fecha de la población
     * @param String fecha
     */
    public void setFecha(String fecha) {
        this.fecha = fecha;
        
        fireModeloPoblacionPropertyChange(new
                        PoblacionPropertyEvent(this, 
                        CHANGE_FECHA));
    }

    /**
     * Devuelve el tamaño de la población
     * @return int tamanioPoblacion
     */
    public int getTamanioPoblacion() {
        return tamanioPoblacion;
    }

    /**
     * Establece el nuevo tamaño de la población
     * @param int tamanioPoblacion
     */
    public void setTamanioPoblacion(int tamanioPoblacion) {
        this.tamanioPoblacion = tamanioPoblacion;
        
        fireModeloPoblacionPropertyChange(new
                        PoblacionPropertyEvent(this, 
                        CHANGE_TAMANIO_POBLACION));
    }

    /**
     * Devuelve la temperatura de la población
     * @return int temperatura
     */
    public int getTemperatura() {
        return temperatura;
    }

    /**
     * Establece la nueva temperatura de la población
     * @param int temperatura
     */
    public void setTemperatura(int temperatura) {
        this.temperatura = temperatura;
        
        fireModeloPoblacionPropertyChange(new
                        PoblacionPropertyEvent(this, 
                        CHANGE_TEMPERATURA));
    }

    /**
     * Devuelve la escala de la temperatura de la población
     * @return String escalaTemperatura
     */
    public String getEscalaTemperatura() {
        return escalaTemperatura;
    }

    /**
     * Establece la nueva escala de la temperatura de la población
     * @param String escalaTemperatura
     */
    public void setEscalaTemperatura(String escalaTemperatura) {
        this.escalaTemperatura = escalaTemperatura;
        
        fireModeloPoblacionPropertyChange(new
                        PoblacionPropertyEvent(this, 
                        CHANGE_ESCALA_TEMPERATURA));
    }

    /**
     * Devuelve la luminosidad de la población
     * @return String luminosidad
     */
    public String getLuminosidad() {
        return luminosidad;
    }

    /**
     * Establece la nueva luminosidad de la población
     * @param String luminosidad
     */
    public void setLuminosidad(String luminosidad) {
        this.luminosidad = luminosidad;
        
        fireModeloPoblacionPropertyChange(new
                        PoblacionPropertyEvent(this, 
                        CHANGE_LUMINOSIDAD));
    }

    /**
     * Devuelve el modelo de la gráfica de la comida
     * @return ModeloGraficaComida modeloGraficaComida
     */
    public ModeloGraficaComida getModeloGraficaComida() {
        return modeloGraficaComida;
    }

    /**
     * Establece el nuevo modelo de la gráfica de la comida
     * @param ModeloGraficaComida
     */
    public void setModeloGraficaComida(ModeloGraficaComida modeloGraficaComida) {
        this.modeloGraficaComida = modeloGraficaComida;
        
        modeloGraficaComida.addChangeEventListener(
                new GraficaComidaChangeEventListener() {
            @Override
            public void fireChangeEvent(GraficaComidaChangeEvent gcce) {
                modeloGraficaChange();
            }
            
        });
        
        fireModeloPoblacionPropertyChange(new
                        PoblacionPropertyEvent(this, 
                        CHANGE_MODELO_GRAFICA));
    }

    /**
     * Devuelve el modelo de la tabla de la población
     * @return ModeloPoblacionTabla modeloPoblacionTabla
     */
    public ModeloPoblacionTabla getModeloPoblacionTabla() {
        return modeloPoblacionTabla;
    }

    /**
     * Establece el nuevo modelo de la tabla de la población
     * @param ModeloPoblacionTabla modeloPoblacionTabla
     */
    public void setModeloPoblacionTabla(ModeloPoblacionTabla modeloPoblacionTabla) {
        this.modeloPoblacionTabla = modeloPoblacionTabla;
        
        modeloPoblacionTabla.addTableModelListener(new TableModelListener() {
            @Override
            public void tableChanged(TableModelEvent e) {
                modeloPoblacionChange();
            }
         });
        
        fireModeloPoblacionPropertyChange(new
                        PoblacionPropertyEvent(this, 
                        CHANGE_MODELO_POBLACION_GRAFICA));
    }
    
    /**
     * Devuelve el modelo de los comentarios de la población
     * @return ModeloComentarios modeloComentarios
     */
    public ModeloComentarios getModeloComentarios() {
        return modeloComentarios;
    }
    
    /**
     * Establece el nuevo modelo de los comentarios de la población
     * @param ModeloComentarios modeloComentarios
     */
    public void setModeloComentarios(ModeloComentarios modeloComentarios) {
        this.modeloComentarios = modeloComentarios;
        
        modeloComentarios.addComentarioListener(new ComentarioListener() {
            @Override
            public void addedComentario(ComentarioEvent ce) {
                modeloComentarioChange();
            }

            @Override
            public void removedComentario(ComentarioEvent ce) {
                modeloComentarioChange();
            }            
        });
        
        fireModeloPoblacionPropertyChange(new
                        PoblacionPropertyEvent(this, 
                        CHANGE_MODELO_COMENTARIOS));
    }
}
